package com.lagou.edu.factory;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.lagou.edu.annotation.AutowiredDiy;
import com.lagou.edu.annotation.ServiceDiy;
import com.lagou.edu.annotation.TransactionalDiy;
import com.lagou.edu.utils.ClassUtils;
import com.lagou.edu.utils.ConnectionUtils;
import com.lagou.edu.utils.DruidUtils;

import java.lang.reflect.*;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;

/**
 * @author 应癫
 *
 * 工厂类，生产对象（使用反射技术）
 */
public class BeanFactory {

    /**
     * 任务一：读取解析xml，通过反射技术实例化对象并且存储待用（map集合）
     * 任务二：对外提供获取实例对象的接口（根据id获取）
     */
    // 存储对象
    private static Map<String,Object> map = new HashMap<>();
    private static Class annotationTypeAutowire;
    /**
     * ServiceDiy
     */
    private static Class annotationTypeService;
    /**
     * TransactionalDiy
     */
    private static Class annotationTypeTransaction;

    static {
        try {
            // 扫描的包下所有class文件
            List<Class<?>> classes = ClassUtils.getClasses("com.lagou.edu");
            // 1. ServiceDiy
            annotationTypeService = Class.forName("com.lagou.edu.annotation.ServiceDiy");
            for (Class<?> aClass : classes) {
                if(!aClass.isInterface()){
                    serviceSupport(aClass);
                }
            }

            // 2.AutowiredDiy
            annotationTypeAutowire = Class.forName("com.lagou.edu.annotation.AutowiredDiy");
            for (Class<?> aClass : classes) {
                if(!aClass.isInterface()){
                    autoWiredSupport(aClass);
                }
            }

            // 3. TransactionDiy
            annotationTypeTransaction = Class.forName("com.lagou.edu.annotation.TransactionalDiy");
            for (Class<?> aClass : classes) {
                if(!aClass.isInterface()){
                    transactionSupport(aClass);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    // 任务二：对外提供获取实例对象的接口（根据id获取）
    public static  Object getBean(String id) {
        System.out.println(id);
        return map.get(id);
    }

    /**
     * 功能描述: <br>
     * 服务注册注解解释器
     * @param aClass
     * @author 18067515
     * @date 2020.7.1 10:57
     */
    public static void serviceSupport(Class aClass) throws IllegalAccessException, InstantiationException {
        ServiceDiy serviceDiy = (ServiceDiy) aClass.getAnnotation(annotationTypeService);
        // 塞选有@ServiceDiy注解的类
        if(null != serviceDiy){
            // 获取注解的初始值
            String key;
            if(serviceDiy.id().equals("")){
                // 没有设定id值，使用类名首字母小写TransferServiceImpl -> transferServiceImpl
                String wholeName ;
                Class<?>[] interfaces = aClass.getInterfaces();
                if(interfaces.length > 0){
                    wholeName = interfaces[0].getName();
                }else{
                    wholeName = aClass.getName();
                }
                key = getHandleId(wholeName);
            }else{
                key = serviceDiy.id();
            }
            if(null == map.get(key)){
                // 未被初始化
                map.put(key,aClass.newInstance());
            }
        }
    }

    /**
     * 功能描述: <br>
     * 依赖注入注解解释器
     * @param clazz 类全路径
     * @author Isaac
     * @date 2020.7.1 10:56
     */
    public static void autoWiredSupport(Class clazz) throws IllegalAccessException, InstantiationException, InvocationTargetException {
            // 类中声明方法集合
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field field : declaredFields) {
                //私有属性暴力访问
                if(!field.isAccessible()){
                    field.setAccessible(true);
                }
                // 注解
                AutowiredDiy annotation = (AutowiredDiy) field.getAnnotation(annotationTypeAutowire);
                // 塞选具有@AutowiredDiy的属性
                if(null != annotation){
                    String parentObjId;
                    Class[] interfaces = clazz.getInterfaces();
                    // 获取父节点[接口名id]，[类名id] （实现接口的类用接口名，未实现接口类用类名）
                    if(interfaces.length>0){
                        parentObjId = getHandleId(interfaces[0].getName());
                    }else {
                        parentObjId = getHandleId(clazz.getName());
                    }

                    Object parentObj = null;
                    if(null == map.get(parentObjId)){
                        // 父类未注册
                        parentObj = clazz.newInstance();
                    }else {
                        // 父类已注册
                        parentObj = map.get(parentObjId);
                    }

                    // com.lagou.edu.dao.AccountDao -> AccountDao
                    String fieldId = field.getType().getName().substring(field.getType().getName().lastIndexOf(".")+1);
                    Method[] methods = parentObj.getClass().getMethods();
                    for (Method method : methods) {
                        // 找到setAccountDao方法，注入属性值
                        if( method.getName().equalsIgnoreCase("set" + fieldId)){
                            String refId;
                            if(annotation.id().equals("")){
                                refId = getHandleId(field.getType().getName());
                            }else{
                                refId = annotation.id();
                            }
                            method.invoke(parentObj,map.get(refId));
                        }
                    }
                    // 将依赖注入后的类放回map
                    map.put(parentObjId,parentObj);
                }

            }



    }

    /**
     * 功能描述: <br>
     * 实现对事务控制注解的解释器
     *
     * @param clazz 类对象
     * @author Isaac
     * @date 2020.7.1 10:55
     */
    public static void transactionSupport(Class clazz) throws IllegalAccessException, InstantiationException, SQLException {
        // 获取@transaction注解，该注解下所有的方法就应该被事务控制，即应该使用代理类注册
        // 事务控制
        // transferServiceImpl
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            // 存在事务控制注解，返回代理对象
            TransactionalDiy transactionalDiy = (TransactionalDiy) declaredMethod.getAnnotation(annotationTypeTransaction);
            if(null != transactionalDiy){
                String parentObjId;
                boolean hasInterface = false;
                Class[] interfaces = clazz.getInterfaces();
                // 获取父节点[接口名id]，[类名id] （实现接口的类用接口名，未实现接口类用类名）
                if(interfaces.length>0){
                    hasInterface = true;
                    parentObjId = getHandleId(interfaces[0].getName());
                }else {
                    parentObjId = getHandleId(clazz.getName());
                }

                if(null != map.get(parentObjId)){
                    Object parentObj = map.get(parentObjId);
                    //数据库连接
                    ConnectionUtils connectionUtils = (ConnectionUtils) map.get("connectionUtils");
                    Connection connection = connectionUtils.getCurrentThreadConn();
                    Object proxyObj = null;
                    if(hasInterface){
                        // 有实现接口 【JDK 动态代理】
                        proxyObj = ProxyFactory.getJdkProxy(parentObj,connection);
                    }else{
                        // 无实现接口 cglib 动态代理
                        proxyObj = ProxyFactory.getCglibProxy(parentObj,connection);
                    }
                    // 将代理对象放回
                    map.put(parentObjId,proxyObj);
                }
            }
        }
    }

    private static String getHandleId(String wholeName){
        String key = wholeName.substring(wholeName.lastIndexOf(".")+1);
        if(key.charAt(0) < 'a'){
            char c = (char) (key.charAt(0) + 32);
            key = key.replaceFirst(String.valueOf(key.charAt(0)), String.valueOf(c));
        }
        return key;
    }

}
